import unittest
from unittest.mock import Mock, patch, MagicMock
import sys
import os

# 添加项目路径到sys.path
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from MySQLDatabaseTool import MySQLDatabaseTool


class TestMySQLDatabaseTool(unittest.TestCase):
    """MySQLDatabaseTool类的测试用例"""

    def setUp(self):
        """测试前的准备工作"""
        self.db_tool = MySQLDatabaseTool(
            host='localhost',
            port=3306,
            user='test_user',
            password='test_password',
            database='test_db'
        )

    def test_init(self):
        """测试初始化方法"""
        self.assertEqual(self.db_tool.host, 'localhost')
        self.assertEqual(self.db_tool.port, 3306)
        self.assertEqual(self.db_tool.user, 'test_user')
        self.assertEqual(self.db_tool.password, 'test_password')
        self.assertEqual(self.db_tool.database, 'test_db')
        self.assertIsNone(self.db_tool.connection)
        self.assertIsNone(self.db_tool.cursor)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_connect_success(self, mock_connect):
        """测试数据库连接成功"""
        # 模拟连接成功
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection

        result = self.db_tool.connect()
        
        self.assertTrue(result)
        self.assertEqual(self.db_tool.connection, mock_connection)
        self.assertEqual(self.db_tool.cursor, mock_cursor)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_connect_failure(self, mock_connect):
        """测试数据库连接失败"""
        # 模拟连接失败
        mock_connect.side_effect = Exception("连接失败")
        
        result = self.db_tool.connect()
        
        self.assertFalse(result)
        self.assertIsNone(self.db_tool.connection)
        self.assertIsNone(self.db_tool.cursor)

    def test_close(self):
        """测试关闭数据库连接"""
        # 模拟已连接状态
        mock_cursor = Mock()
        mock_connection = Mock()
        mock_connection.is_connected.return_value = True
        self.db_tool.cursor = mock_cursor
        self.db_tool.connection = mock_connection
        
        self.db_tool.close()
        
        mock_cursor.close.assert_called_once()
        mock_connection.close.assert_called_once()

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_create_database_success(self, mock_connect):
        """测试创建数据库成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.create_database("new_db")
        
        self.assertTrue(result)
        mock_cursor.execute.assert_called_once()

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_create_database_failure(self, mock_connect):
        """测试创建数据库失败"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_cursor.execute.side_effect = Exception("创建失败")
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.create_database("new_db")
        
        self.assertFalse(result)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_show_databases_success(self, mock_connect):
        """测试查看数据库列表成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        mock_cursor.fetchall.return_value = [
            {'Database': 'db1'},
            {'Database': 'db2'}
        ]
        
        result = self.db_tool.show_databases()
        
        self.assertIsNotNone(result)
        self.assertEqual(result, ['db1', 'db2'])

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_show_databases_failure(self, mock_connect):
        """测试查看数据库列表失败"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_cursor.fetchall.side_effect = Exception("查询失败")
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.show_databases()
        
        self.assertIsNone(result)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_use_database_success(self, mock_connect):
        """测试切换数据库成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.use_database("new_db")
        
        self.assertTrue(result)
        self.assertEqual(self.db_tool.database, "new_db")

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_use_database_failure(self, mock_connect):
        """测试切换数据库失败"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_cursor.execute.side_effect = Exception("切换失败")
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.use_database("new_db")
        
        self.assertFalse(result)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_drop_database_success(self, mock_connect):
        """测试删除数据库成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.drop_database("old_db")
        
        self.assertTrue(result)
        mock_cursor.execute.assert_called_once()

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_drop_database_failure(self, mock_connect):
        """测试删除数据库失败"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_cursor.execute.side_effect = Exception("删除失败")
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.drop_database("old_db")
        
        self.assertFalse(result)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_create_table_success(self, mock_connect):
        """测试创建表成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        columns = [
            {'name': 'id', 'type': 'INT', 'primary_key': True, 'auto_increment': True},
            {'name': 'name', 'type': 'VARCHAR(50)', 'not_null': True},
            {'name': 'age', 'type': 'INT', 'default': 0}
        ]
        
        result = self.db_tool.create_table("test_table", columns)
        
        self.assertTrue(result)
        mock_cursor.execute.assert_called_once()

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_create_table_failure(self, mock_connect):
        """测试创建表失败"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_cursor.execute.side_effect = Exception("创建失败")
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        columns = [
            {'name': 'id', 'type': 'INT', 'primary_key': True}
        ]
        
        result = self.db_tool.create_table("test_table", columns)
        
        self.assertFalse(result)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_describe_table_success(self, mock_connect):
        """测试查看表结构成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        mock_cursor.fetchall.return_value = [
            {'Field': 'id', 'Type': 'int', 'Null': 'NO', 'Key': 'PRI', 'Default': None, 'Extra': 'auto_increment'},
            {'Field': 'name', 'Type': 'varchar(50)', 'Null': 'NO', 'Key': '', 'Default': None, 'Extra': ''}
        ]
        
        result = self.db_tool.describe_table("test_table")
        
        self.assertIsNotNone(result)
        self.assertEqual(len(result), 2)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_describe_table_failure(self, mock_connect):
        """测试查看表结构失败"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_cursor.fetchall.side_effect = Exception("查询失败")
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.describe_table("test_table")
        
        self.assertIsNone(result)

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_drop_table_success(self, mock_connect):
        """测试删除表成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.drop_table("old_table")
        
        self.assertTrue(result)
        mock_cursor.execute.assert_called_once()

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_add_column_success(self, mock_connect):
        """测试新增字段成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        column = {'name': 'email', 'type': 'VARCHAR(100)', 'default': ''}
        result = self.db_tool.add_column("test_table", column)
        
        self.assertTrue(result)
        mock_cursor.execute.assert_called_once()

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_modify_column_success(self, mock_connect):
        """测试修改字段成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        column = {'name': 'name', 'type': 'VARCHAR(100)', 'not_null': True}
        result = self.db_tool.modify_column("test_table", column)
        
        self.assertTrue(result)
        mock_cursor.execute.assert_called_once()

    @patch('MySQLDatabaseTool.mysql.connector.connect')
    def test_drop_column_success(self, mock_connect):
        """测试删除字段成功"""
        mock_connection = Mock()
        mock_cursor = Mock()
        mock_connection.cursor.return_value = mock_cursor
        mock_connection.is_connected.return_value = True
        mock_connect.return_value = mock_connection
        
        result = self.db_tool.drop_column("test_table", "old_column")
        
        self.assertTrue(result)
        mock_cursor.execute.assert_called_once()


if __name__ == '__main__':
    unittest.main()
